package cn.lili.modules.kit.plugin.apple;

import cn.hutool.json.JSONUtil;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.utils.ResultUtil;
import cn.lili.common.utils.SnowFlake;
import cn.lili.common.utils.StringUtils;
import cn.lili.common.vo.ResultMessage;
import cn.lili.exchange.AmqpExchangeProperties;
import cn.lili.modules.kit.Payment;
import cn.lili.modules.kit.plugin.wallet.WalletPlugin;
import cn.lili.modules.order.order.client.OrderClient;
import cn.lili.modules.order.trade.client.TradeClient;
import cn.lili.modules.payment.entity.dos.PaymentLog;
import cn.lili.modules.payment.entity.dto.PaymentCallback;
import cn.lili.modules.payment.entity.dto.PaymentWakeupParam;
import cn.lili.modules.payment.entity.enums.PaymentSceneEnums;
import cn.lili.modules.payment.entity.vo.ApplePaymentVO;
import cn.lili.modules.payment.service.*;
import cn.lili.modules.system.client.SettingClient;
import cn.lili.modules.system.entity.dos.Setting;
import cn.lili.modules.system.entity.dto.ApplyProductSetting;
import cn.lili.modules.wallet.service.WalletService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;

@Slf4j
@Component
public class ApplePlugin extends WalletPlugin implements Payment {

    @Resource
    private SettingClient settingClient;

    @Resource
    private PaymentLogService paymentLogService;

    @Resource
    private TradeClient tradeClient;

    // 苹果的测试服
    private static final String APP_STORE_PRIVATE_RECEIPT = "https://sandbox.itunes.apple.com/verifyReceipt";
    // 苹果的生产服
    private static final String APP_STORE_PUBLIC_RECEIPT = "https://buy.itunes.apple.com/verifyReceipt";

    public ApplePlugin(ApplicationEventPublisher applicationEventPublisher, AmqpExchangeProperties amqpExchangeProperties,
                       WalletService walletService, PaymentLogService paymentLogService, OutOrderLogService outOrderLogService,
                       OutOrderDetailLogService outOrderDetailLogService, PaymentSubsidiesService paymentSubsidiesService,
                       PaymentUrbanSubstationCommissionService paymentUrbanSubstationCommissionService, OrderClient orderClient) {
        super(applicationEventPublisher, amqpExchangeProperties, walletService, paymentLogService, outOrderLogService,
                outOrderDetailLogService, paymentSubsidiesService, paymentUrbanSubstationCommissionService, orderClient);
    }

    /**
     * H5支付
     */
    @Override
    public ResultMessage<Object> h5pay(PaymentWakeupParam paymentWakeupParam) {
        ApplePaymentVO applyPaymentVO = new ApplePaymentVO();
        applyPaymentVO.setOutTradeNo(SnowFlake.getIdStr());
        applyPaymentVO.setTransactionId(SnowFlake.getIdStr());
        PaymentLog paymentLog = paymentWakeupParam.getPaymentLog();
        paymentLog.setOutTradeNo(applyPaymentVO.getOutTradeNo());
        // 获取apply支付的产品ID
        Setting setting = settingClient.get("APPLY_PRODUCT_SETTING");
        ApplyProductSetting applyProductSetting = JSONUtil.toBean(setting.getSettingValue(), ApplyProductSetting.class);
        // plus会员支付场景
        if (PaymentSceneEnums.VIP.name().equals(paymentWakeupParam.getPayParam().getPaymentSceneEnums().name())) {
            // plus会员的productID
            applyPaymentVO.setProductId(applyProductSetting.getPlusVip());
            return ResultUtil.data(applyPaymentVO);
        }
        return ResultUtil.error(500, "获取Apply支付参数失败");
    }

    /**
     * 支付成功回调
     */
    @Override
    public void paymentNotify(ApplePaymentVO applePaymentVO) {
        log.info("paymentNotify:{},{},{}", applePaymentVO.getOutTradeNo(), applePaymentVO.getTransactionId(), applePaymentVO.getReceipt());
        Assert.isTrue(StringUtils.isNotEmpty(applePaymentVO.getOutTradeNo()), ResultCode.PARAMS_ERROR.message());
        PaymentLog paymentLog = paymentLogService.getPaymentLogByOutTradeNo(applePaymentVO.getOutTradeNo());
        if(paymentLog == null || paymentLog.getIsPay()){
            return;
        }
        Assert.isTrue(StringUtils.isNotEmpty(applePaymentVO.getReceipt()), ResultCode.PARAMS_ERROR.message());
        String sendPost = sendPost(APP_STORE_PUBLIC_RECEIPT, "{\"receipt-data\":\"" + applePaymentVO.getReceipt() + "\"}");
        log.info("苹果内购订单返回值,receiveMsg,{}", sendPost);
        JSONObject object = JSON.parseObject(sendPost);
        int status = (int) object.get("status");
        // 支付成功
        if (status == 0) {
            JSONObject receiptInfo = object.getJSONObject("receipt");
            JSONArray inAppList = receiptInfo.getJSONArray("in_app");
            if(!CollectionUtils.isEmpty(inAppList)){
                JSONObject inApp = inAppList.getJSONObject(inAppList.size() - 1);
                // 票据ID
                String transactionId = inApp.getString("transaction_id");
                paymentLog.setTransactionId(transactionId);
                paymentLog.setIsPay(true);
            }
        }else if (status == 21007) { // 苹果内购沙箱环境
            String sendPrivatePost = sendPost(APP_STORE_PRIVATE_RECEIPT, "{\"receipt-data\":\"" + applePaymentVO.getReceipt() + "\"}");
            log.info("苹果内购沙箱环境订单返回值,receiveMsg,{}", sendPrivatePost);
            JSONObject privateJson = JSON.parseObject(sendPrivatePost);
            int privateStatus = (int) privateJson.get("status");
            if (privateStatus == 0) {
                JSONObject receiptInfo = privateJson.getJSONObject("receipt");
                JSONArray inAppList = receiptInfo.getJSONArray("in_app");
                if(!CollectionUtils.isEmpty(inAppList)){
                    JSONObject inApp = inAppList.getJSONObject(inAppList.size() - 1);
                    // 票据ID
                    String transactionId = inApp.getString("transaction_id");
                    paymentLog.setTransactionId(transactionId);
                    paymentLog.setIsPay(true);
                }
            }
        }else {
            throw new ServiceException("支付失败");
        }
        //标记已检查
        paymentLog.setIsCheck(true);
        paymentLogService.updateById(paymentLog);
        // 支付状态为TRUE才进行通知
        if (paymentLog.getIsPay().equals(true)) {
            PaymentCallback paymentCallback = PaymentCallback.builder().paymentLog(paymentLog).isCombine(false).build();
            tradeClient.paymentCallback(paymentCallback);
        }
    }

    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url
     *            发送请求的 URL
     * @param param
     *            请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        StringBuilder sb = new StringBuilder();
        PrintWriter out = null;
        BufferedReader in = null;
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            sb = new StringBuilder();
            while ((line = in.readLine()) != null) {
                sb.append(line);
            }
        } catch (Exception e) {
            log.error("post请求异常：{}", e.getMessage());
        }
        // 使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                log.error("io异常：{}", ex.getMessage());
            }
        }
        return sb.toString();
    }
}